#include "Log.h"
#include <Channel.h>
#include <cstddef>
#include <cstdint>
#include <sys/epoll.h>
#include <EventLoop.h>

namespace muduo{
    Channel::Channel(EventLoop* loop,int fd):_loop(loop),_fd(fd),_events(0),_revents(0){}
    int Channel::Fd(){return _fd;}
    void Channel::SetEvents(uint32_t events){_revents=events;}
    uint32_t Channel::events(){return _events;}
    void Channel::DisableAll(){_events=0;Update();}
    bool Channel::ReadAble(){return _events == EPOLLIN;}
    bool Channel::WriterAble(){return _events == EPOLLOUT;}
    void Channel::EnableRead(){_events |= EPOLLIN;Update();}
    void Channel::EnableWrite(){_events |= EPOLLOUT;Update();}
    void Channel::CloseRead(){_events &= ~EPOLLIN;Update();}
    void Channel::CloseWrite(){_events &= ~EPOLLOUT;Update();}
    void Channel::Set_read_callback(const EventsCallback& cb){_read_callback=cb;}
    void Channel::Set_write_callback(const EventsCallback& cb){_writ_callback=cb;}
    void Channel::Set_error_callback(const EventsCallback& cb){_error_callback=cb;}
    void Channel::Set_close_callback(const EventsCallback& cb){_close_callback=cb;}
    void Channel::Set_event_callback(const EventsCallback& cb){_event_callback=cb;}
    void Channel::HanderEvents(){
        // EPOLLRDHUP对端关闭连接或半连接，EPOLLPRI对端发送紧急数据
        if(_revents & EPOLLIN || _revents & EPOLLRDHUP || _revents & EPOLLPRI){
            // if(_event_callback){_event_callback();}
            if(_read_callback){
                _read_callback();
            }
        }
        // 以下是可能会关闭连接的事件
        // 注意：可能会关闭连接的事件只处理一次，因为如果连接被关闭且被监控事件中还有其它事件满足if，则会出错
        // 所以将多个if合并为if else
        if(_revents & EPOLLOUT){
            if(_event_callback){_event_callback();}
            if(_writ_callback){_writ_callback();}
        }else if(_revents & EPOLLERR){
            if(_event_callback){_event_callback();}
            if(_error_callback){_error_callback();}
        }else if(_revents & EPOLLHUP){
            if(_event_callback){_event_callback();}
            if(_close_callback){_close_callback();}
        }
    }
    void Channel::Remove(){_loop->RemoveEvent(this);}
    void Channel::Update(){_loop->UpdateEvent(this);}
}